﻿//==============================================================================
// File: PropertiesViewer.xaml.cs
// Created: 2010-05-28
// Author: Piotr Włodek, Arek Świerczek
//==============================================================================
// This file is a part of MAMMOTH project.
// Copyright (C) 2010 AGH University of Science and Technology, Krakow.
// https://caribou.iisg.agh.edu.pl/trac/mammoth
//
// Mammoth is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// Mammoth is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with Mammoth. If not, see http://www.gnu.org/licenses/.
//==============================================================================

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.ComponentModel;
using System.Windows.Controls;

namespace WpfRcp.Controls
{
    /// <summary>
    /// Interaction logic for PropertiesViewer.xaml
    /// </summary>
    public partial class PropertiesViewer
    {
        public PropertiesViewer()
        {
            InitializeComponent();
            ValueColumnWidth = new DataGridLength(1.0, DataGridLengthUnitType.Star);
        }

        public DataGridLength ValueColumnWidth
        {
            get { return (DataGridLength)GetValue(ValueColumnWidthProperty); }
            set { SetValue(ValueColumnWidthProperty, value); }
        }

        public static readonly DependencyProperty ValueColumnWidthProperty =
            DependencyProperty.Register("ValueColumnWidth", typeof(DataGridLength), typeof(PropertiesViewer), new FrameworkPropertyMetadata(new DataGridLength(1.0, DataGridLengthUnitType.Star), ValueColumnWidthChanged));

        private static void ValueColumnWidthChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var viewer = (PropertiesViewer) obj;

            if(viewer.Columns.Count == 2)
            {
                viewer.Columns[1].Width = (DataGridLength) e.NewValue;
            }
        }

        private void OnPropertyViewerLoaded(object sender, RoutedEventArgs e)
        {
            Columns[1].Width = ValueColumnWidth;
        }
    }

    [Serializable]
    public class PropertyItem : INotifyPropertyChanged, IEditableObject
    {
        private string m_Name;
        private PropertyType m_PropertyType;
        private bool m_IsReadOnly = true;
        private bool m_BoolValue;
        private int m_IntValue;
        private string m_StringValue;
        private Enum m_EnumValue;
        private bool m_IsMultiLineString;
        private bool m_IsSeparator;
        private object m_Tag;
        private object m_Value;
        private readonly ObservableCollection<EnumContainer> m_EnumValues = new ObservableCollection<EnumContainer>();
        private readonly ObservableCollection<ValueContainer> m_Values = new ObservableCollection<ValueContainer>();
        
        public PropertyItem()
        {
        }

        public PropertyItem(string name)
        {
            Name = name;
            IsSeparator = true;
        }

        public PropertyItem(string name, bool value, bool isReadOnly): this(name, value)
        {
            IsReadOnly = isReadOnly;
        }

        public PropertyItem(string name, bool value)
        {
            Name = name;
            BoolValue = value;
        }

        public PropertyItem(string name, int  value, bool isReadOnly)
            : this(name, value)
        {
            IsReadOnly = isReadOnly;
        }

        public PropertyItem(string name, int value)
        {
            Name = name;
            IntValue = value;
        }

        public PropertyItem(string name, string value, bool isMultiLineString, bool isReadOnly)
            : this(name, value, isMultiLineString)
        {
            IsReadOnly = isReadOnly;
        }

        public PropertyItem(string name, string value, bool isMultiLineString)
            : this(name, value)
        {
            IsMultiLineString = isMultiLineString;
        }

        public PropertyItem(string name, string value)
        {
            Name = name;
            StringValue = value;
        }

        public PropertyItem(string name, Enum value, params EnumContainer[] enumValues)
        {
            Name = name;
            EnumValue = value;
            foreach (var container in enumValues)
            {
                EnumValues.Add(container);
            }
            IsReadOnly = false;
        }

        public PropertyItem(string name, object value, params ValueContainer[] values)
        {
            Name = name;
            ObjectValue = value;

            foreach (var container in values)
            {
                Values.Add(container);
            }
            
            IsReadOnly = false;
        }

        public event EventHandler ValueChanged;

        public string Name
        {
            get { return m_Name; }
            set
            {
                m_Name = value;
                OnPropertyChanged("Name");
            }
        }

        public bool BoolValue
        {
            get { return m_BoolValue; }
            set
            {
                m_BoolValue = value;
                m_StringValue = value.ToString();
                OnPropertyChanged("BoolValue");
                OnPropertyChanged("StringValue");

                PropertyType = PropertyType.Bool;
                OnValueChanged();
            }
        }

        public int IntValue
        {
            get { return m_IntValue; }
            set
            {
                m_IntValue = value;
                m_StringValue = value.ToString();
                OnPropertyChanged("IntValue");
                OnPropertyChanged("StringValue");

                PropertyType = PropertyType.Int;
                OnValueChanged();
            }
        }

        public string StringValue
        {
            get { return m_StringValue; }
            set
            {
                m_StringValue = value;
                OnPropertyChanged("StringValue");

                PropertyType = PropertyType.String;
                OnValueChanged();
            }
        }

        public Enum EnumValue
        {
            get { return m_EnumValue; }
            set
            {
                m_EnumValue = value;
                m_StringValue = value.ToString();
                OnPropertyChanged("EnumValue");
                OnPropertyChanged("StringValue");

                PropertyType = PropertyType.Enum;
                OnValueChanged();
            }
        }

        public object ObjectValue
        {
            get { return m_Value; }
            set
            {
                if (m_Value != value)
                {
                    m_Value = value;
                    m_StringValue = value.ToString();
                    OnPropertyChanged("ObjectValue");
                    OnPropertyChanged("StringValue");

                    PropertyType = PropertyType.Object;
                    OnValueChanged();
                }
            }
        }

        public IList<EnumContainer> EnumValues
        {
            get { return m_EnumValues; }
        }

        public ObservableCollection<ValueContainer> Values
        {
            get { return m_Values; }
        }

        public PropertyType PropertyType
        {
            get { return m_PropertyType; }
            private set
            {
                m_PropertyType = value;
                OnPropertyChanged("PropertyType");
            }
        }

        public bool IsReadOnly
        {
            get { return m_IsReadOnly; }
            set
            {
                if (!IsSeparator)
                {
                    m_IsReadOnly = value;
                    OnPropertyChanged("IsReadOnly");
                }
            }
        }

        public bool IsMultiLineString
        {
            get { return m_IsMultiLineString; }
            set
            {
                m_IsMultiLineString = value;
                OnPropertyChanged("IsMultiLineString");
            }
        }

        public bool IsSeparator
        {
            get { return m_IsSeparator; }
            set
            {
                m_IsSeparator = value;
                OnPropertyChanged("IsSeparator");

                if(value)
                {
                    IsReadOnly = true;
                }
            }
        }

        public object Tag
        {
            get { return m_Tag; }
            set
            {
                m_Tag = value;
                OnPropertyChanged("Tag");
            }
        }

        protected void OnValueChanged()
        {
            if(ValueChanged != null)
            {
                ValueChanged(this, EventArgs.Empty);
            }
        }

        #region INotifyPropertyChanged Members

        [field:NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string name)
        {
            if(PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

        #endregion

        #region IEditableObject Members

        private PropertyItem m_Clone;

        //Additional notification for easy database commits
        [field: NonSerialized]
        public event EventHandler EditEnded;

        void IEditableObject.BeginEdit()
        {
            m_Clone = new PropertyItem();
            Copy(this, m_Clone);
        }

        void IEditableObject.CancelEdit()
        {
            Copy(m_Clone, this);
        }

        void IEditableObject.EndEdit()
        {
            m_Clone = null;

            if (EditEnded != null)
            {
                EditEnded(this, EventArgs.Empty);
            }
        }

        private static void Copy(PropertyItem from, PropertyItem to)
        {
            switch (from.PropertyType)
            {
                case PropertyType.Bool:
                    to.BoolValue = from.BoolValue;
                    break;
                case PropertyType.Int:
                    to.IntValue = from.IntValue;
                    break;
                case PropertyType.String:
                    to.StringValue = from.StringValue;
                    break;
                case PropertyType.Enum:
                    to.EnumValue = from.EnumValue;
                    break;
            }
        }

        #endregion
    }

    [Serializable]
    public class EnumContainer
    {
        public EnumContainer(Enum value, string label)
        {
            Value = value;
            Label = label;
        }

        public string Label { get; private set; }

        public Enum Value { get; private set; }
    }

    [Serializable]
    public class ValueContainer
    {
        public ValueContainer(object value, string label)
        {
            Value = value;
            Label = label;
        }

        public string Label { get; private set; }

        public object Value { get; private set; }
    }

    [Serializable]
    public enum PropertyType
    {
        String,
        Bool,
        Int,
        Enum,
        Object
    }
}